
/*
 * Copyright (C) Igor Sysoev
 * Copyright (C) Nginx, Inc.
 */


#ifndef _NGX_EVENT_H_INCLUDED_
#define _NGX_EVENT_H_INCLUDED_


#include <ngx_config.h>
#include <ngx_core.h>


#define NGX_INVALID_INDEX 0xd0d0d0d0


#if (NGX_HAVE_IOCP)

typedef struct
{
    WSAOVERLAPPED ovlp;
    ngx_event_t  *event;
    int           error;
} ngx_event_ovlp_t;

#endif


struct ngx_event_s
{
    void *data;

    unsigned write : 1;

#if (NGX_SSL && NGX_SSL_ASYNC)
    unsigned async : 1;
#endif

    unsigned accept : 1;

    /* used to detect the stale events in kqueue and epoll */
    unsigned instance : 1;

    /*
     * the event was passed or would be passed to a kernel;
     * in aio mode - operation was posted.
     */
    unsigned active : 1;

    unsigned disabled : 1;

    /* the ready event; in aio mode 0 means that no operation can be posted */
    unsigned ready : 1;

    unsigned oneshot : 1;

    /* aio operation is complete */
    unsigned complete : 1;

    unsigned eof   : 1;
    unsigned error : 1;

    unsigned timedout  : 1;
    unsigned timer_set : 1;

    unsigned delayed : 1;

    unsigned deferred_accept : 1;

    /* the pending eof reported by kqueue, epoll or in aio chain operation */
    unsigned pending_eof : 1;

    unsigned posted : 1;

    unsigned closed : 1;

    /* to test on worker exit */
    unsigned channel  : 1;
    unsigned resolver : 1;

    unsigned cancelable : 1;

#if (NGX_HAVE_KQUEUE)
    unsigned kq_vnode : 1;

    /* the pending errno reported by kqueue */
    int kq_errno;
#endif

    /*
     * kqueue only:
     *   accept:     number of sockets that wait to be accepted
     *   read:       bytes to read when event is ready
     *               or lowat when event is set with NGX_LOWAT_EVENT flag
     *   write:      available space in buffer when event is ready
     *               or lowat when event is set with NGX_LOWAT_EVENT flag
     *
     * iocp: TODO
     *
     * otherwise:
     *   accept:     1 if accept many, 0 otherwise
     *   read:       bytes to read when event is ready, -1 if not known
     */

    int available;

    ngx_event_handler_pt handler;
#if (NGX_SSL && NGX_SSL_ASYNC)
    ngx_event_handler_pt saved_handler;
#endif


#if (NGX_HAVE_IOCP)
    ngx_event_ovlp_t ovlp;
#endif

    ngx_uint_t index;

    ngx_log_t *log;

    ngx_rbtree_node_t timer;

    /* the posted queue */
    ngx_queue_t queue;

#if 0

    /* the threads support */

    /*
     * the event thread context, we store it here
     * if $(CC) does not understand __thread declaration
     * and pthread_getspecific() is too costly
     */

    void            *thr_ctx;

#if (NGX_EVENT_T_PADDING)

    /* event should not cross cache line in SMP */

    uint32_t         padding[NGX_EVENT_T_PADDING];
#endif
#endif
};


#if (NGX_HAVE_FILE_AIO)

struct ngx_event_aio_s
{
    void                *data;
    ngx_event_handler_pt handler;
    ngx_file_t          *file;

    ngx_fd_t fd;

#if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT)
    ssize_t (*preload_handler)(ngx_buf_t *file);
#endif

#if (NGX_HAVE_EVENTFD)
    int64_t res;
#endif

#if !(NGX_HAVE_EVENTFD) || (NGX_TEST_BUILD_EPOLL)
    ngx_err_t err;
    size_t    nbytes;
#endif

    ngx_aiocb_t aiocb;
    ngx_event_t event;
};

#endif


typedef struct
{
    ngx_int_t (*add)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
    ngx_int_t (*del)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);

    ngx_int_t (*enable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
    ngx_int_t (*disable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);

    ngx_int_t (*add_conn)(ngx_connection_t *c);
    ngx_int_t (*del_conn)(ngx_connection_t *c, ngx_uint_t flags);

    ngx_int_t (*notify)(ngx_event_handler_pt handler);

    ngx_int_t (*process_events)(ngx_cycle_t *cycle, ngx_msec_t timer,
                                ngx_uint_t flags);

    ngx_int_t (*init)(ngx_cycle_t *cycle, ngx_msec_t timer);
    void (*done)(ngx_cycle_t *cycle);

#if (NGX_SSL && NGX_SSL_ASYNC)
    ngx_int_t (*add_async_conn)(ngx_connection_t *c);
    ngx_int_t (*del_async_conn)(ngx_connection_t *c, ngx_uint_t flags);
#endif
} ngx_event_actions_t;


extern ngx_event_actions_t ngx_event_actions;
#if (NGX_HAVE_EPOLLRDHUP)
extern ngx_uint_t ngx_use_epoll_rdhup;
#endif
#if (T_NGX_ACCEPT_FILTER)
typedef ngx_int_t (*ngx_event_accept_filter_pt)(ngx_connection_t *c);
void ngx_close_accepted_connection(ngx_connection_t *c);
extern ngx_event_accept_filter_pt ngx_event_top_accept_filter;
#endif


/*
 * The event filter requires to read/write the whole data:
 * select, poll, /dev/poll, kqueue, epoll.
 */
#define NGX_USE_LEVEL_EVENT 0x00000001

/*
 * The event filter is deleted after a notification without an additional
 * syscall: kqueue, epoll.
 */
#define NGX_USE_ONESHOT_EVENT 0x00000002

/*
 * The event filter notifies only the changes and an initial level:
 * kqueue, epoll.
 */
#define NGX_USE_CLEAR_EVENT 0x00000004

/*
 * The event filter has kqueue features: the eof flag, errno,
 * available data, etc.
 */
#define NGX_USE_KQUEUE_EVENT 0x00000008

/*
 * The event filter supports low water mark: kqueue's NOTE_LOWAT.
 * kqueue in FreeBSD 4.1-4.2 has no NOTE_LOWAT so we need a separate flag.
 */
#define NGX_USE_LOWAT_EVENT 0x00000010

/*
 * The event filter requires to do i/o operation until EAGAIN: epoll.
 */
#define NGX_USE_GREEDY_EVENT 0x00000020

/*
 * The event filter is epoll.
 */
#define NGX_USE_EPOLL_EVENT 0x00000040

/*
 * Obsolete.
 */
#define NGX_USE_RTSIG_EVENT 0x00000080

/*
 * Obsolete.
 */
#define NGX_USE_AIO_EVENT 0x00000100

/*
 * Need to add socket or handle only once: i/o completion port.
 */
#define NGX_USE_IOCP_EVENT 0x00000200

/*
 * The event filter has no opaque data and requires file descriptors table:
 * poll, /dev/poll.
 */
#define NGX_USE_FD_EVENT 0x00000400

/*
 * The event module handles periodic or absolute timer event by itself:
 * kqueue in FreeBSD 4.4, NetBSD 2.0, and MacOSX 10.4, Solaris 10's event ports.
 */
#define NGX_USE_TIMER_EVENT 0x00000800

/*
 * All event filters on file descriptor are deleted after a notification:
 * Solaris 10's event ports.
 */
#define NGX_USE_EVENTPORT_EVENT 0x00001000

/*
 * The event filter support vnode notifications: kqueue.
 */
#define NGX_USE_VNODE_EVENT 0x00002000


/*
 * The event filter is deleted just before the closing file.
 * Has no meaning for select and poll.
 * kqueue, epoll, eventport:         allows to avoid explicit delete,
 *                                   because filter automatically is deleted
 *                                   on file close,
 *
 * /dev/poll:                        we need to flush POLLREMOVE event
 *                                   before closing file.
 */
#define NGX_CLOSE_EVENT 1

/*
 * disable temporarily event filter, this may avoid locks
 * in kernel malloc()/free(): kqueue.
 */
#define NGX_DISABLE_EVENT 2

/*
 * event must be passed to kernel right now, do not wait until batch processing.
 */
#define NGX_FLUSH_EVENT 4


/* these flags have a meaning only for kqueue */
#define NGX_LOWAT_EVENT 0
#define NGX_VNODE_EVENT 0


#if (NGX_HAVE_EPOLL) && !(NGX_HAVE_EPOLLRDHUP)
#define EPOLLRDHUP 0
#endif


#if (NGX_HAVE_KQUEUE)

#define NGX_READ_EVENT  EVFILT_READ
#define NGX_WRITE_EVENT EVFILT_WRITE

#undef NGX_VNODE_EVENT
#define NGX_VNODE_EVENT EVFILT_VNODE

/*
 * NGX_CLOSE_EVENT, NGX_LOWAT_EVENT, and NGX_FLUSH_EVENT are the module flags
 * and they must not go into a kernel so we need to choose the value
 * that must not interfere with any existent and future kqueue flags.
 * kqueue has such values - EV_FLAG1, EV_EOF, and EV_ERROR:
 * they are reserved and cleared on a kernel entrance.
 */
#undef NGX_CLOSE_EVENT
#define NGX_CLOSE_EVENT EV_EOF

#undef NGX_LOWAT_EVENT
#define NGX_LOWAT_EVENT EV_FLAG1

#undef NGX_FLUSH_EVENT
#define NGX_FLUSH_EVENT EV_ERROR

#define NGX_LEVEL_EVENT   0
#define NGX_ONESHOT_EVENT EV_ONESHOT
#define NGX_CLEAR_EVENT   EV_CLEAR

#undef NGX_DISABLE_EVENT
#define NGX_DISABLE_EVENT EV_DISABLE


#elif (NGX_HAVE_DEVPOLL && !(NGX_TEST_BUILD_DEVPOLL)) \
    || (NGX_HAVE_EVENTPORT && !(NGX_TEST_BUILD_EVENTPORT))

#define NGX_READ_EVENT  POLLIN
#define NGX_WRITE_EVENT POLLOUT

#define NGX_LEVEL_EVENT   0
#define NGX_ONESHOT_EVENT 1


#elif (NGX_HAVE_EPOLL) && !(NGX_TEST_BUILD_EPOLL)

#define NGX_READ_EVENT  (EPOLLIN | EPOLLRDHUP)
#define NGX_WRITE_EVENT EPOLLOUT

#define NGX_LEVEL_EVENT   0
#define NGX_CLEAR_EVENT   EPOLLET
#define NGX_ONESHOT_EVENT 0x70000000
#if 0
#define NGX_ONESHOT_EVENT EPOLLONESHOT
#endif

#if (NGX_HAVE_EPOLLEXCLUSIVE)
#define NGX_EXCLUSIVE_EVENT EPOLLEXCLUSIVE
#endif

#elif (NGX_HAVE_POLL)

#define NGX_READ_EVENT  POLLIN
#define NGX_WRITE_EVENT POLLOUT

#define NGX_LEVEL_EVENT   0
#define NGX_ONESHOT_EVENT 1


#else /* select */

#define NGX_READ_EVENT  0
#define NGX_WRITE_EVENT 1

#define NGX_LEVEL_EVENT   0
#define NGX_ONESHOT_EVENT 1

#endif /* NGX_HAVE_KQUEUE */


#if (NGX_HAVE_IOCP)
#define NGX_IOCP_ACCEPT  0
#define NGX_IOCP_IO      1
#define NGX_IOCP_CONNECT 2
#endif


#if (NGX_TEST_BUILD_EPOLL)
#define NGX_EXCLUSIVE_EVENT 0
#endif


#ifndef NGX_CLEAR_EVENT
#define NGX_CLEAR_EVENT 0 /* dummy declaration */
#endif


#define ngx_process_events ngx_event_actions.process_events
#define ngx_done_events    ngx_event_actions.done

#define ngx_add_event ngx_event_actions.add
#define ngx_del_event ngx_event_actions.del
#define ngx_add_conn  ngx_event_actions.add_conn
#define ngx_del_conn  ngx_event_actions.del_conn

#if (NGX_SSL && NGX_SSL_ASYNC)
#define ngx_add_async_conn ngx_event_actions.add_async_conn
#define ngx_del_async_conn ngx_event_actions.del_async_conn
#endif

#define ngx_notify ngx_event_actions.notify

#define ngx_add_timer ngx_event_add_timer
#define ngx_del_timer ngx_event_del_timer


extern ngx_os_io_t ngx_io;

#define ngx_recv           ngx_io.recv
#define ngx_recv_chain     ngx_io.recv_chain
#define ngx_udp_recv       ngx_io.udp_recv
#define ngx_send           ngx_io.send
#define ngx_send_chain     ngx_io.send_chain
#define ngx_udp_send       ngx_io.udp_send
#define ngx_udp_send_chain ngx_io.udp_send_chain


#define NGX_EVENT_MODULE 0x544E5645 /* "EVNT" */
#define NGX_EVENT_CONF   0x02000000


typedef struct
{
    ngx_uint_t connections;
    ngx_uint_t use;

    ngx_flag_t multi_accept;
    ngx_flag_t accept_mutex;

    ngx_msec_t accept_mutex_delay;

    u_char *name;

#if (NGX_DEBUG)
    ngx_array_t debug_connection;
#endif
} ngx_event_conf_t;


typedef struct
{
    ngx_str_t *name;

    void *(*create_conf)(ngx_cycle_t *cycle);
    char *(*init_conf)(ngx_cycle_t *cycle, void *conf);

    ngx_event_actions_t actions;
} ngx_event_module_t;


extern ngx_atomic_t *ngx_connection_counter;

extern ngx_atomic_t *ngx_accept_mutex_ptr;
extern ngx_shmtx_t   ngx_accept_mutex;
extern ngx_uint_t    ngx_use_accept_mutex;
extern ngx_uint_t    ngx_accept_events;
extern ngx_uint_t    ngx_accept_mutex_held;
extern ngx_msec_t    ngx_accept_mutex_delay;
extern ngx_int_t     ngx_accept_disabled;


#if (NGX_STAT_STUB)

extern ngx_atomic_t *ngx_stat_accepted;
extern ngx_atomic_t *ngx_stat_handled;
extern ngx_atomic_t *ngx_stat_requests;
extern ngx_atomic_t *ngx_stat_active;
extern ngx_atomic_t *ngx_stat_reading;
extern ngx_atomic_t *ngx_stat_writing;
extern ngx_atomic_t *ngx_stat_waiting;
#if (T_NGX_HTTP_STUB_STATUS)
extern ngx_atomic_t *ngx_stat_request_time;
#endif
#endif


#define NGX_UPDATE_TIME 1
#define NGX_POST_EVENTS 2


extern sig_atomic_t ngx_event_timer_alarm;
extern ngx_uint_t   ngx_event_flags;
extern ngx_module_t ngx_events_module;
extern ngx_module_t ngx_event_core_module;


#define ngx_event_get_conf(conf_ctx, module) \
    (*(ngx_get_conf(conf_ctx, ngx_events_module)))[module.ctx_index]


void ngx_event_accept(ngx_event_t *ev);
#if !(NGX_WIN32)
void ngx_event_recvmsg(ngx_event_t *ev);
void ngx_udp_rbtree_insert_value(ngx_rbtree_node_t *temp,
                                 ngx_rbtree_node_t *node,
                                 ngx_rbtree_node_t *sentinel);
#endif
void      ngx_delete_udp_connection(void *data);
ngx_int_t ngx_trylock_accept_mutex(ngx_cycle_t *cycle);
ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle);
u_char   *ngx_accept_log_error(ngx_log_t *log, u_char *buf, size_t len);
#if (NGX_DEBUG)
void ngx_debug_accepted_connection(ngx_event_conf_t *ecf, ngx_connection_t *c);
#endif


void      ngx_process_events_and_timers(ngx_cycle_t *cycle);
ngx_int_t ngx_handle_read_event(ngx_event_t *rev, ngx_uint_t flags);
ngx_int_t ngx_handle_write_event(ngx_event_t *wev, size_t lowat);


#if (NGX_WIN32)
void      ngx_event_acceptex(ngx_event_t *ev);
ngx_int_t ngx_event_post_acceptex(ngx_listening_t *ls, ngx_uint_t n);
u_char   *ngx_acceptex_log_error(ngx_log_t *log, u_char *buf, size_t len);
#endif


ngx_int_t ngx_send_lowat(ngx_connection_t *c, size_t lowat);


/* used in ngx_log_debugX() */
#define ngx_event_ident(p) ((ngx_connection_t *)(p))->fd


#include <ngx_event_timer.h>
#include <ngx_event_posted.h>

#if (NGX_WIN32)
#include <ngx_iocp_module.h>
#endif


#endif /* _NGX_EVENT_H_INCLUDED_ */
